//
//  HierarchicalObject.m
//  CocoaMoney
//
//  Created by Daniel Braun on 14/10/06.
//  Copyright 2006 Daniel Braun http://braun.daniel.free.fr. All rights reserved.
//

#import "HierarchicalObject.h"
#import "HOfilterProtocol.h"

@implementation HierarchicalObject
- (id) init {
	self = [super init];
	if (self != nil) {
		//FLD
	}
	return self;
}

- (void) dealloc {
	//FLD
	[parent release];
	[children release];
	[super dealloc];
}

- (void)encodeWithCoder:(NSCoder *)coder
{
	// FLD
	//[super encodeWithCoder:coder];
	if ( [coder allowsKeyedCoding] ) {
		[coder encodeObject:children forKey:@"children"];
		[coder encodeObject:parent forKey:@"parent"];
	} else {
		NSAssert(0, @"only key coder supported\n");
	}
}


- (id) initWithCoder:(NSCoder *) coder
{
	//self=[super initWithCoder:coder];
	self=[super init];
	if ([coder allowsKeyedCoding]) {
		children=[[coder decodeObjectForKey:@"children"]retain];
		parent=[[coder decodeObjectForKey:@"parent"]retain];
	}
	return self;
}

- (void) _removeChild:(id)s
{
	[children removeObject:s]; 
}

- (id) parent
{
	return parent;
}
- (void) setParent:(id)s
{
	if (parent==self) return;
	if (parent) {
		[parent willChangeValueForKey:@"children"];
		[parent _removeChild:self];
		[parent didChangeValueForKey:@"children"];
		[parent release];
	}
	parent=[s retain];
}

- (NSMutableArray *) children
{
	if (!children) {
		children=[[NSMutableArray arrayWithCapacity:10] retain];
	}	
	return children;
}
- (id) firstChild
{
	if (!children) return nil;
	if (![children count]) return nil;
	return [children objectAtIndex:0];
}
- (void) setChildren:(NSMutableArray *)a
{
	[children release];
	children=[a retain];
	unsigned int i, count = [a count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * obj = [a objectAtIndex:i];
		NSAssert([obj isKindOfClass:[HierarchicalObject class]], @"bad class for setChildren");
		if (![obj parent]) [obj setParent:self];
	}
}
- (void) addChild:(id)c
{
	[self willChangeValueForKey:@"children"];
	if (!children) {
		children=[[NSMutableArray arrayWithCapacity:10] retain];
	}
	[children addObject:c];
	[c setParent: self];
	[self didChangeValueForKey:@"children"];
}

- (int) count
{
	return children ? [children count] : 0;
}

- (BOOL) isLeaf
{
	if (0==[self count]) return YES;
	return NO;
}
- (int) level
{
	if (!parent) {
		//NSLog(@"no parent\n");
		return 0;
	}
	//NSLog(@"has parent\n");
	return [parent level]+1;
}

- (NSString *)indentString
{
	int l=[self level];
	return [@"" stringByPaddingToLength: l*4 withString: @" " startingAtIndex:0];
}


- (NSArray *) flatList
{
	NSMutableArray *r=[NSMutableArray arrayWithCapacity:[children count]*2];
	[r addObject:self];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * c = [children objectAtIndex:i];
		[r addObjectsFromArray:[c flatList]];
	}
	return r;
}

- (NSArray *) flatListUsingFilter:(NSObject <HierarchicalObjectFiltering>*)filter
{
	NSMutableArray *r=[NSMutableArray arrayWithCapacity:[children count]*2];
	if ([filter shouldAccept:self]) [r addObject:self];
	if ([filter shouldRecurse:self]) {
		unsigned int i, count = [children count];
		for (i = 0; i < count; i++) {
			HierarchicalObject * c = [children objectAtIndex:i];
			[r addObjectsFromArray:[c flatListUsingFilter:filter]];
		}
	}
	return r;	
}

- (int) _one
{
	return 1;
}

- (void) recurseSelector:(SEL) sel
{
	[self performSelector:sel];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * obj = [children objectAtIndex:i];
		[obj recurseSelector:sel];
	}
}

- (id) recurseSelectorUntilNotil:(SEL) sel
{
	id r=[self performSelector:sel];
	if (r) return r;
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * obj = [children objectAtIndex:i];
		r=[obj recurseSelectorUntilNotil:sel];
		if (r) return r;
	}
	return nil;
}

- (id) recurseSelectorUntilNotil:(SEL) sel  withObject:(id)arg
{
	id r=[self performSelector:sel withObject:arg];
	if (r) return r;
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * obj = [children objectAtIndex:i];
		r=[obj recurseSelectorUntilNotil:sel withObject:arg];
		if (r) return r;
	}
	return nil;
}


- (void) recurseSelector:(SEL) sel withObject:(id)arg
{
	[self recurseSelector:sel then:(SEL)0 withObject:arg];
}

- (void) recurseSelector:(SEL) sel then:(SEL)sel2 withObject:(id)arg;
{
	[self performSelector:sel withObject:arg];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * obj = [children objectAtIndex:i];
		[obj recurseSelector:sel then:sel2 withObject:arg];
	}
	if (sel2) [self performSelector:sel2 withObject:arg];
}
- (void) recurseSelector:(SEL) sel inArray:(NSMutableArray *)results
{
	id r;
	r=[self performSelector:sel];
	if (r) [results addObject:r];
	else [results addObject:[NSNull null]];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		NSObject * obj = [children objectAtIndex:i];
		r=[obj performSelector:sel];
		if (r) [results addObject:r];
		else [results addObject:[NSNull null]];
	}
}

- (void) recurseSelector:(SEL) sel withObject:(id)arg inArray:(NSMutableArray *)results
{
	id r;
	r=[self performSelector:sel withObject:arg];
	if (r) [results addObject:r];
	else [results addObject:[NSNull null]];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		NSObject * obj = [children objectAtIndex:i];
		r=[obj performSelector:sel withObject:arg];
		if (r) [results addObject:r];
		else [results addObject:[NSNull null]];
	}
}

- (int) recurseIntAddSelector:(SEL) sel
{
	long k;
	k=(long) [self performSelector:sel];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		NSObject * obj = [children objectAtIndex:i];
		k+=(int)[(HierarchicalObject *)obj recurseIntAddSelector:sel];
	}
	return k;
}

- (int) recurseIntAddSelector:(SEL) sel withObject:(id)arg
{
	long k;
	k=(long)[self performSelector:sel withObject:arg];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		NSObject * obj = [children objectAtIndex:i];
		k+=(long)[obj performSelector:sel withObject:arg];
	}
	return k;
}
- (double)  recurseDoubleAddSelector:(SEL) sel
{
	return [self recurseDoubleAddSelector:sel includingSelf:YES];
}

- (double)  recurseDoubleAddSelector:(SEL) sel includingSelf:(BOOL) doself
{
	double k=0.0;
	NSInvocation *inv=[NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
	[inv setSelector:sel];

	if (doself) {
		[inv setTarget:self];
		[inv invoke];
		[inv getReturnValue:&k];
	}
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		NSObject * obj = [children objectAtIndex:i];
		[inv setTarget:obj];
		[inv invoke];
		double v;
		[inv getReturnValue:&v];
		k+=v;
	}
	return k;
}
- (double) recurseDoubleAddSelector:(SEL) sel withObject:(id)arg
{
	double k;
	NSInvocation *inv=[NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
	[inv setSelector:sel];
	[inv setArgument:arg atIndex:2];
	[inv setTarget:self];
	[inv getReturnValue:&k];
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		NSObject * obj = [children objectAtIndex:i];
		[inv setTarget:obj];
		[inv invoke];
		double v;
		[inv getReturnValue:&v];
		k+=v;
	}
	return k;
}

- (int) gCount
{
	return [self recurseIntAddSelector:@selector(_one)];
}

- (BOOL) contains:(HierarchicalObject *)c
{
	if (c==self) return YES;
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * obj = [children objectAtIndex:i];
		if ([obj contains:c]) return YES;
	}
	return NO;
}

- (void) _checkParentShouldBe:(HierarchicalObject *)p
{
	if (!parent) {
		NSLog(@"parent not set, fixing!\n"); //DB6 fix
		parent=[p retain];
	}
	NSAssert(parent==p, @"bad parent");
}

- (void) _checkParent
{
	unsigned int i, count = [children count];
	for (i = 0; i < count; i++) {
		HierarchicalObject * ho = [children objectAtIndex:i];
		[ho _checkParentShouldBe:self];
	}
}

- (void) checkParent
{
	[self recurseSelector:@selector(_checkParent)];
}

#if 0
- (BOOL)isKindOfClass:(Class)aClass
{
	NSLog(@"%@: isKindOfClass:%@\n", [self className], [aClass className]);
	return [super isKindOfClass:aClass];
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
	return [super respondsToSelector:aSelector];
}
#endif
@end
